﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
using BE.Web.Betfair.Interface.Requests;
using System.Reflection;
using System.Diagnostics;

namespace BE.Web.Betfair.Interface.Entities
{
    /// <summary>
    /// A betfair market
    /// </summary>
    [DebuggerDisplay("{DateTimeGMT} - {Name}")]
    public sealed class BetMarket
    {
        /// <summary>
        /// The Id of the Market
        /// </summary>
        public int Id { get; private set; }

        /// <summary>
        /// Name of the Market
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// Type of the Market
        /// </summary>
        public string Type { get; private set; }

        /// <summary>
        /// Status of the Market
        /// </summary>
        public string Status { get; private set; }

        /// <summary>
        /// The date of the associated Market
        /// </summary>
        /// <value>The date time GMT.</value>
        public DateTimeOffset DateTimeGMT { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="BetMarket"/> class.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="name">The caption.</param>
        public BetMarket(int id,string name)
        {
            this.Id = id;
            this.Name = name;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BetMarket"/> class.
        /// </summary>
        public BetMarket()
        {

        }



        /// <summary>
        /// Creates a readonly Colleciton of betmarkets by the given remote response string
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns>ReadOnlyCollection of all markets</returns>
        public static ReadOnlyCollection<BetMarket> FromResponseString(string data)
        {
            #region conditions
            Contract.Requires<ArgumentNullException>(data != null);
            Contract.Requires<ArgumentException>(!String.IsNullOrWhiteSpace(data));
            Contract.Ensures(Contract.Result<ReadOnlyCollection<BetMarket>>() != null);
            #endregion

            List<BetMarket> markets;

            string[] entries = data.Split(':');

            markets = new List<BetMarket>(entries.Length);
            BetMarket curMarket;

            Parallel.ForEach<string>(entries,
                curEntry =>
                {

                    if (!string.IsNullOrWhiteSpace(curEntry))
                    {
                        curMarket = ToMarket(curEntry);
                        markets.Add(curMarket);
                    }
                });

            return new ReadOnlyCollection<BetMarket>(markets);
        }

        [ContractInvariantMethod]
        void ObjectInvariant()
        {
            Contract.Invariant(Fields != null);
        }

        static BetMarket()
        {
            Contract.Ensures(Fields != null);
            Type marketType = typeof(BetMarket);

            Fields = new List<BetMarketField>(16);
            Fields.Add(new BetMarketField(0, marketType.GetProperty("Id")));
            Fields.Add(new BetMarketField(1, marketType.GetProperty("Name")));
            Fields.Add(new BetMarketField(2, marketType.GetProperty("Type")));
            Fields.Add(new BetMarketField(3, marketType.GetProperty("Status")));
            Fields.Add(new BetMarketField(4, marketType.GetProperty("DateTimeGMT")));
        }

        private static BetMarket ToMarket(string marketRow)
        {
            #region conditions
            Contract.Requires<ArgumentNullException>(marketRow != null);
            Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(marketRow));
            Contract.Ensures(Contract.Result<BetMarket>() != null);
            #endregion

            BetMarket result = new BetMarket();

            string[] stringfields = marketRow.Split('~');

            if (stringfields != null && stringfields.Length > 0)
            {
                string stringVal;
                object targetValue;
                Type marketType = typeof(BetMarket);
                
                foreach (BetMarketField curField in Fields)
                {

                    if (curField != null && curField.FieldIndex < stringfields.Length)
                    {
                        stringVal = stringfields[curField.FieldIndex];

                        if (!String.IsNullOrWhiteSpace(stringVal) && curField.TargetProperty != null && curField.TargetProperty.PropertyType != null )
                        {
                            if(curField.TargetProperty.PropertyType == typeof(string))
                            {
                            
                                targetValue = stringVal;
                            }
                            else if (curField.TargetProperty.PropertyType == typeof(DateTimeOffset))
                            {
                              
                                double time = Convert.ToDouble(stringVal);
                                DateTime temp = new DateTime(1970, 1, 1).AddSeconds(time / 1000);

                                DateTimeOffset offset = new DateTimeOffset(temp, TimeSpan.Zero);
                                targetValue = offset;
                            }
                            else
                            {
                              
                                targetValue = Convert.ChangeType(stringVal, curField.TargetProperty.PropertyType);
                            }

                            curField.TargetProperty.SetValue(result, targetValue, null);
                        }
                    }
                }

                string eventHirachie = stringfields[6];

                if (!String.IsNullOrWhiteSpace(eventHirachie))
                {
                    addEventHirachie(result, eventHirachie);
                }

            }



            return result;
        }

        private static void addEventHirachie(BetMarket market,string events)
        {
            Contract.Requires<ArgumentNullException>(market != null);
            Contract.Requires<ArgumentNullException>(events != null);

            BetEvent rootEvent = null;

            string[] eventList = events.Split('/');

            if (eventList != null && eventList.Length > 0)
            {
                rootEvent = new BetEvent(Convert.ToInt32(eventList[1]), "", new BetEventType(0, "", 0, 0), DateTime.MinValue, 0, null, null);
                BetEvent parent = rootEvent;
                BetEvent curEvent;
                for (int i = 2; i < eventList.Length; i++)
                {
                    curEvent = new BetEvent(Convert.ToInt32(eventList[i]), "",new BetEventType(0,"",0,0), DateTime.MinValue, 0, null, null);
                    parent.SubEvents.Add(curEvent);
                    parent = curEvent;
                }
            }

            if (rootEvent != null)
            { }
        }
        private static List<BetMarketField> Fields { get; set; }

        private static object getFieldValue<T>(string[] fields, int fieldIndex,Type typeofField)
        {
            object result;
            result = Convert.ChangeType(fields[(int)fieldIndex], typeofField);
            return result;
        }

      


    }
}
